package com.wyman.aop.framework;

import com.wyman.aop.AdvisedSupport;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
 * @Author 李伟民
 * @Description
 * @DateTime 2025/1/7 20:23
 */
public class Cglib2AopProxy implements AopProxy{

    private final AdvisedSupport advisedSupport;

    public Cglib2AopProxy(AdvisedSupport advisedSupport){
        this.advisedSupport = advisedSupport;
    }


    private static class CglibMethodInvocation extends ReflectiveMethodInvocation{

        private final MethodProxy methodProxy;

        private CglibMethodInvocation(Object target, Method method, Object[] arguments,MethodProxy methodProxy) {
            super(target,method,arguments);
            this.methodProxy = methodProxy;
        }

        @Override
        public Object proceed() throws Throwable {
            return this.methodProxy.invoke(this.target,this.arguments);
        }
    }

    private static class DynamicAdvisedInterceptor implements MethodInterceptor {

        private final AdvisedSupport advisedSupport;
        public DynamicAdvisedInterceptor (AdvisedSupport advisedSupport){
            this.advisedSupport = advisedSupport;
        }
        @Override
        public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
            CglibMethodInvocation methodInvocation = new CglibMethodInvocation(advisedSupport.getTargetSource().getTarget(), method, objects, methodProxy);
            if(advisedSupport.getMethodMatcher().matches(method,advisedSupport.getTargetSource().getClass())){
                return advisedSupport.getMethodInterceptor().invoke(methodInvocation);
            }
            return methodInvocation.proceed();
        }
    }



    @Override
    public Object getProxy() {

        Enhancer enhancer = new Enhancer();
        Class<?> clazz= advisedSupport.getTargetSource().getTarget().getClass();
        clazz = isCglibProxyClass(clazz)?clazz.getSuperclass():clazz;

        enhancer.setSuperclass(clazz);
        enhancer.setCallback(new DynamicAdvisedInterceptor(advisedSupport));
        enhancer.setInterfaces(advisedSupport.getTargetSource().getTargetClass());
        return enhancer.create();
    }


    public static boolean isCglibProxyClass(Class<?> clazz) {
        return (clazz != null && isCglibProxyClassName(clazz.getName()));
    }

    /**
     * Check whether the specified class name is a CGLIB-generated class.
     * @param className the class name to check
     */
    public static boolean isCglibProxyClassName(String className) {
        return (className != null && className.contains("$$"));
    }
}
